﻿Imports System.IO
Imports System.Text

Public Class ClsCSV

    Sub New()

    End Sub
    ''' <summary>
    ''' DataTableの内容をCSVファイルに保存する
    ''' </summary>
    ''' <param name="dt">CSVに変換するDataTable</param>
    ''' <param name="csvPath">保存先のCSVファイルのパス</param>
    ''' <param name="writeHeader">ヘッダを書き込む時はtrue。</param>
    Public Sub ConvertDataTableToCsv( _
            dt As DataTable, csvPath As String, writeHeader As Boolean)
        'CSVファイルに書き込むときに使うEncoding
        'Dim enc As System.Text.Encoding = _
        '    System.Text.Encoding.GetEncoding("UTF-8")
        Dim utf8 As New UTF8Encoding()
        Dim utf8EmitBOM As New UTF8Encoding(False)

        '書き込むファイルを開く
        Dim sr As New System.IO.StreamWriter(csvPath, False, utf8EmitBOM)
        'sr.Write(utf8EmitBOM.GetPreamble())

        Dim colCount As Integer = dt.Columns.Count
        Dim lastColIndex As Integer = colCount - 1
        Dim i As Integer

        'ヘッダを書き込む
        If writeHeader Then
            For i = 0 To colCount - 1
                'ヘッダの取得
                Dim field As String = dt.Columns(i).Caption
                '"で囲む
                field = EncloseDoubleQuotesIfNeed(field)
                'フィールドを書き込む
                sr.Write(field)
                'カンマを書き込む
                If lastColIndex > i Then
                    sr.Write(","c)
                End If
            Next
            '改行する
            sr.Write(vbCrLf)
        End If

        'レコードを書き込む
        Dim row As DataRow
        For Each row In dt.Rows
            For i = 0 To colCount - 1
                'フィールドの取得
                Dim field As String = row(i).ToString()
                '"で囲む
                field = EncloseDoubleQuotesIfNeed(field)
                'フィールドを書き込む
                sr.Write(field)
                'カンマを書き込む
                If lastColIndex > i Then
                    sr.Write(","c)
                End If
            Next
            '改行する
            sr.Write(vbCrLf)
        Next

        '閉じる
        sr.Close()
    End Sub

    ''' <summary>
    ''' 必要ならば、文字列をダブルクォートで囲む
    ''' </summary>
    Private Function EncloseDoubleQuotesIfNeed(field As String) As String
        If NeedEncloseDoubleQuotes(field) Then
            Return EncloseDoubleQuotes(field)
        End If
        Return field
    End Function

    ''' <summary>
    ''' 文字列をダブルクォートで囲む
    ''' </summary>
    Private Function EncloseDoubleQuotes(field As String) As String
        If field.IndexOf(""""c) > -1 Then
            '"を""とする
            field = field.Replace("""", """""")
        End If
        Return """" & field & """"
    End Function

    ''' <summary>
    ''' 文字列をダブルクォートで囲む必要があるか調べる
    ''' </summary>
    Private Function NeedEncloseDoubleQuotes(field As String) As Boolean
        Return field.IndexOf(""""c) > -1 OrElse _
            field.IndexOf(","c) > -1 OrElse _
            field.IndexOf(ControlChars.Cr) > -1 OrElse _
            field.IndexOf(ControlChars.Lf) > -1 OrElse _
            field.StartsWith(" ") OrElse _
            field.StartsWith(vbTab) OrElse _
            field.EndsWith(" ") OrElse _
            field.EndsWith(vbTab)
    End Function




    'dt:保存すべきデータ
    'hasHeader:CSVファイルの1行目にカラム名を入れるか
    'separator:カラムとカラムの間の文字(,など)
    'quote:カラムを囲む文字
    'replace:"などのエスケープの仕方
    Public Sub ConvertDataTableToCsv(ByVal dt As DataTable, ByVal fileName As String, ByVal hasHeader As Boolean, ByVal separator As String, ByVal quote As String, ByVal replace As String)
        Dim rows As Integer = dt.Rows.Count
        Dim cols As Integer = dt.Columns.Count
        Dim text As String
        '保存用のファイルを開く。上書きモードで。
        Dim writer As StreamWriter = New StreamWriter(fileName, False, Encoding.GetEncoding("UTF-8"))
        'カラム名を保存するか
        If hasHeader Then
            'カラム名を保存する場合
            For i As Integer = 0 To cols - 1 Step 1
                'カラム名を取得
                If quote <> "" Then
                    text = dt.Columns(i).ColumnName.Replace(quote, replace)
                Else
                    text = dt.Columns(i).ColumnName
                End If

                If i <> cols - 1 Then
                    writer.Write(quote + text + quote + separator)
                Else
                    writer.WriteLine(quote + text + quote)
                End If
            Next
        End If

        'データの保存処理
        For i As Integer = 0 To rows - 1 Step 1
            For j As Integer = 0 To cols - 1 Step 1
                'クォートが指定されているか
                If quote <> "" Then
                    '指定されている場合エスケープしておく
                    text = dt.Rows(i)(j).ToString().Replace(quote, replace)
                Else
                    text = dt.Rows(i)(j).ToString()
                End If

                If j <> cols - 1 Then
                    '行の最後のカラムでない場合は後ろにまだカラムが続くので、separatorを入れておく
                    writer.Write(quote + text + quote + separator)
                Else
                    writer.WriteLine(quote + text + quote)
                End If
            Next j
        Next i
        'ストリームを閉じる
        writer.Close()
    End Sub
End Class
